/*
 * DxDiag
 *
 * Copyright 2008 Allen Hair <allen.hair@gmail.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 *
 */
#include "dxdiag_res.h"
#include "dxdiagcom.h"

#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "wchar.h"

#include "wine/unicode.h"
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(dxdiag);

HINSTANCE hInstance;
HWND hTabDisplay;
HWND hTabCtrl;

SystemInfo systemInfo;
DisplayInfo displayInfo;
FilesInfo filesInfo;
SoundInfo soundInfo;
MusicInfo musicInfo;
InputInfo inputInfo;
NetworkInfo networkInfo;

/* System tab callback proceedure */
LRESULT CALLBACK HelpTab_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg) {
        case WM_INITDIALOG:
            return TRUE;
        default:
            break;
    }

    return FALSE;
}

void DxDiag_SaveText(LPWSTR filename)
{
    /* Open the file */
    FILE* pFile;
    pFile = fopen(filename, "w");

    /* Write the sysInfo data to the file */
    System_SaveText(pFile);
    Display_SaveText(pFile);
    Files_SaveText(pFile);
    Sound_SaveText(pFile);
    Input_SaveText(pFile);

    /* Close the file */
    fclose(pFile);
}

void DxDiag_SaveXML(LPWSTR filename)
{
    FILE* pFile;
    XML_Node* current;
    /* Build the tree */
    XML_Node* rootNode = XML_initializeNode("DxDiag", NULL);

    current = XML_insertChildNode(rootNode, DxDiag_LoadString(MAIN_XML_SYSTEMINFORMATION), NULL);
    System_SaveXML(current);
    current = XML_insertChildNode(rootNode, DxDiag_LoadString(MAIN_XML_DISPLAYDEVICES), NULL);
    Display_SaveXML(current);
    current = XML_insertChildNode(rootNode, DxDiag_LoadString(MAIN_XML_DIRECTSOUND), NULL);
    Sound_SaveXML(current);
    current = XML_insertChildNode(rootNode, DxDiag_LoadString(MAIN_XML_DIRECTXCOMPONENTS), NULL);
    Files_SaveXML(current);
    current = XML_insertChildNode(rootNode, DxDiag_LoadString(MAIN_XML_DIRECTMUSIC), NULL);
    /* TODO: Music_SaveXML */
    current = XML_insertChildNode(rootNode, DxDiag_LoadString(MAIN_XML_DIRECTINPUT), NULL);
    Input_SaveXML(current);

    /* Open the file */
    pFile = fopen(filename, "w");

    /* Write the tree to the file */
    fwprintf(pFile,("<?xml version=\"1.0\"?>\n"));

    XML_parseTree(rootNode, pFile);

    /* Free the tree */
    XML_freeTree(rootNode);

    /* Close the file */
    fclose(pFile);
}

BOOL DxDiag_SaveInfo(HWND hWnd)
{
    OPENFILENAME  ofn;
    WCHAR filter[] = {'T','e','x','t',' ','f','i','l','e','\\','0','*','.','t','x','t','\\','0','X','M','L',' ','f','i','l','e','\\','0','*','.','x','m','l','\\','0','0'};
    WCHAR filename[1024];
    ZeroMemory(&filename, 1024*sizeof(WCHAR));
    ZeroMemory(&ofn, sizeof(OPENFILENAME));

    /* Set the parameters for the save file dialog box */
    ofn.lStructSize = sizeof(OPENFILENAME);
    ofn.hwndOwner = hWnd;
    ofn.hInstance = hInstance;
    ofn.lpstrFilter = filter;
    ofn.lpstrFile = filename;
    ofn.nMaxFile = 1024;
    ofn.Flags = OFN_HIDEREADONLY;

    /* Display the dialog box and get the save location */
    if (!GetSaveFileName(&ofn))
    {
        int error;
        /* If there was no error, just return */
        if ((error = CommDlgExtendedError()) == 0) return TRUE;

        /* TODO: Error reporting */
        return FALSE;
    }

    /* Determine the type of file */
    switch (ofn.nFilterIndex) {
        case 1:
            /* TODO: Save in plaintext format */
            DxDiag_SaveText(filename);
            break;

        case 2:
            /* TODO: Save in xml format */
            DxDiag_SaveXML(filename);
            break;
    }

    return TRUE;
}

/* Function to update the currently displayed tab */
BOOL DxDiag_SelectTab(UINT i)
{
    /* Destroy the current tab */
    if (hTabDisplay != NULL) DestroyWindow(hTabDisplay);

    /* Create the appropriate tab to display */
    switch (i) {
        case 0:
            hTabDisplay = CreateDialog(hInstance,
                                        MAKEINTRESOURCE(SYSTEMTAB_DLG),
                                        hTabCtrl, System_DlgProc);
            System_DisplayData();
            break;
        case 1:
            hTabDisplay = CreateDialog(hInstance,
                                        MAKEINTRESOURCE(FILESTAB_DLG),
                                        hTabCtrl, Files_DlgProc);
            Files_DisplayData();
            break;
        case 2:
            hTabDisplay = CreateDialog(hInstance,
                                        MAKEINTRESOURCE(DISPLAYTAB_DLG),
                                        hTabCtrl, Display_DlgProc);
            Display_DisplayData();
            break;
        case 3:
            hTabDisplay = CreateDialog(hInstance,
                                        MAKEINTRESOURCE(SOUNDTAB_DLG),
                                        hTabCtrl, Sound_DlgProc);
            Sound_DisplayData();
            break;
        case 4:
            hTabDisplay = CreateDialog(hInstance,
                                        MAKEINTRESOURCE(MUSICTAB_DLG),
                                        hTabCtrl, Music_DlgProc);
                Music_DisplayData();
            break;
        case 5:
            hTabDisplay = CreateDialog(hInstance,
                                        MAKEINTRESOURCE(INPUTTAB_DLG),
                                        hTabCtrl, Input_DlgProc);
            Input_DisplayData();
            break;
        case 6:
            hTabDisplay = CreateDialog(hInstance,
                                        MAKEINTRESOURCE(NETWORKTAB_DLG),
                                        hTabCtrl, Network_DlgProc);
                Network_DisplayData();
            break;
        case 7:
            hTabDisplay = CreateDialog(hInstance,
                                        MAKEINTRESOURCE(HELPTAB_DLG),
                                        hTabCtrl, HelpTab_DlgProc);
            break;
        default:
            break;
    }

    /* If the tab wasn't created */
    if (!hTabDisplay)
    {
        /* TODO: Error reporting */
        return FALSE;
    }

    return TRUE;
}

/* Function to create the tab controller */
BOOL DxDiag_CreateTabCtrl(HWND hWnd)
{
    HFONT font;
    TCITEM tie;
    WCHAR buf[1024];

    /* Create the tab controller */
    hTabCtrl = CreateWindow(WC_TABCONTROL, 0, WS_CHILD | WS_VISIBLE | WS_TABSTOP, 11, 11, 703, 448, hWnd, NULL, hInstance, NULL);
    if (!hTabCtrl)
    {
        /* TODO: Error Logging */
        return FALSE;
    }

    /* Add the tabs */
    tie.mask = TCIF_TEXT;
    LoadString(hInstance, SYSTEMTAB_CAPTION, buf, 1024);
    tie.pszText = buf;
    TabCtrl_InsertItem(hTabCtrl, 0, &tie);
    LoadString(hInstance, FILESTAB_CAPTION, buf, 1024);
    tie.pszText = buf;
    TabCtrl_InsertItem(hTabCtrl, 1, &tie);
    LoadString(hInstance, DISPLAYTAB_CAPTION, buf, 1024);
    tie.pszText = buf;
    TabCtrl_InsertItem(hTabCtrl, 2, &tie);
    LoadString(hInstance, SOUNDTAB_CAPTION, buf, 1024);
    tie.pszText = buf;
    TabCtrl_InsertItem(hTabCtrl, 3, &tie);
    LoadString(hInstance, MUSICTAB_CAPTION, buf, 1024);
    tie.pszText = buf;
    TabCtrl_InsertItem(hTabCtrl, 4, &tie);
    LoadString(hInstance, INPUTTAB_CAPTION, buf, 1024);
    tie.pszText = buf;
    TabCtrl_InsertItem(hTabCtrl, 5, &tie);
    LoadString(hInstance, NETWORKTAB_CAPTION, buf, 1024);
    tie.pszText = buf;
    TabCtrl_InsertItem(hTabCtrl, 6, &tie);
    LoadString(hInstance, HELPTAB_CAPTION, buf, 1024);
    tie.pszText = buf;
    TabCtrl_InsertItem(hTabCtrl, 7, &tie);

    /* Set the font for the tabs */
    font = (HFONT)SendMessage(hWnd, WM_GETFONT, 0, 0);
    SendMessage(hTabCtrl, WM_SETFONT, (WPARAM)font, TRUE);

    /* Display the first tab */
    DxDiag_SelectTab(0);

    return TRUE;
}

/* Application callback proceedure */
LRESULT CALLBACK DxDiag_DlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    int i;
    LPNMHDR pnmh;

    /* Process messages */
    switch(uMsg) {
        case WM_INITDIALOG:
            DxDiag_CreateTabCtrl(hWnd);
            return TRUE;

        case WM_NOTIFY:
            pnmh = (LPNMHDR)lParam;
            switch(pnmh->code) {
                case TCN_SELCHANGE:
                    i = TabCtrl_GetCurSel(pnmh->hwndFrom);
                    DxDiag_SelectTab(i);
                    return TRUE;
                default:
                    break;
             }
                    /* Update the displayed tab */
            break;

        case WM_DESTROY:
            /* Shut down the application */
            PostQuitMessage(WM_QUIT);
            return TRUE;

        case WM_COMMAND:
            /* If the Help button was pressed */
            if (LOWORD(wParam) == DXDIAG_HELP) {
                /* TODO: Help Button Proceedure */
                return TRUE;
            }

            /* If the Next button was pressed */
            if (LOWORD(wParam) == DXDIAG_NEXT) {
                     i = TabCtrl_GetCurSel(hTabCtrl);
                     TabCtrl_SetCurFocus(hTabCtrl, i+1);
                return TRUE;
            }

            /* If the Save button was pressed */
            if (LOWORD(wParam) == DXDIAG_SAVE) {
                /* TODO: Save Button Proceedure */
                DxDiag_SaveInfo(hWnd);
                return TRUE;
            }

            /* If the exit button was pressed */
            if (LOWORD(wParam) == DXDIAG_EXIT) {
                /* Shut down the application */
                PostQuitMessage(WM_QUIT);
                return TRUE;
            }
            break;

        case WM_CLOSE:
            /* Close the window */
            DestroyWindow(hWnd);
            return TRUE;

        default:
            break;
    }

    /* Return FALSE for unprocessed messages */
    return FALSE;
}

/* Originally in 'utils.c', but no need to put them separately */
LPWSTR BoolToChoice(BOOL input, LPCWSTR cTrue, LPCWSTR cFalse)
{
    static WCHAR buf[BUF_SIZE];
    WCHAR *newStr;
    if (input)
        wsprintfW(buf,cTrue);
    else
        wsprintfW(buf,cFalse);

    newStr = wcslen(buf);
    wcscpy(newStr,buf);

    return newStr;
}

/* See BoolToChoice */
LPWSTR BoolToYesNo(BOOL input)
{
    return BoolToChoice(input,("Yes"),("No"));
}

/*
 * Load a string from the resource file, handling any error
 * Returns any string retrieved from resource file
 */
WCHAR *DxDiag_LoadString(UINT id) {
    static WCHAR msg[2048];
    static const WCHAR failedMsg[] = { 'F','a','i','l','e','d','!','\0' }; // "Failed!"

    if (!LoadString(GetModuleHandle(NULL), id, msg, sizeof(msg)/sizeof(WCHAR))) {
        WINE_FIXME("LoadString failed with %d\n", GetLastError());
        strcpyW(msg, failedMsg);
    }

    return msg;
}


/* Program entry point */
int WINAPI wWinMain(HINSTANCE hInst, HINSTANCE hPrevInstance, PSTR pCmdLine, int iCmdShow)
{
    /* Declare locals */
    HWND hDlg;
    MSG msg;
    int status;
    DxDiagCOM ddgcom;

    hInstance = hInst;

    /* Initialize COM */
    if (FAILED(DxDiagCOM_Init(&ddgcom)))
        return FALSE;

    /* Get information */
    SystemInfo_GetInfo(&ddgcom, &systemInfo);
    DisplayInfo_GetInfo(&ddgcom, &displayInfo);
    FilesInfo_GetInfo(&ddgcom, &filesInfo);
    SoundInfo_GetInfo(&ddgcom, &soundInfo);
    MusicInfo_GetInfo(&ddgcom, &musicInfo);
    InputInfo_GetInfo(&ddgcom, &inputInfo);
    NetworkInfo_GetInfo(&ddgcom, &networkInfo);

    /* Initialize win32 control classes */
    InitCommonControls();

    /* Create the application window */
    hDlg = CreateDialog(hInst, MAKEINTRESOURCE(DXDIAG_DLG), NULL, DxDiag_DlgProc);
    if (!hDlg)
    {
        /* TODO: Error Logging */
        return FALSE;
    }

    /* Process messages */
    while ((status = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0) {
        if (status == -1)
            return -1;

        if (IsDialogMessage(hDlg, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    /* Return the exit code parameter */
    return msg.wParam;
}
